package com.dlc.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.allinpay.service.AllinpayCompanyService;
import com.dlc.shop.bean.app.param.PayParam;
import com.dlc.shop.bean.app.param.PayUserParam;
import com.dlc.shop.bean.bo.PayInfoResultBO;
import com.dlc.shop.bean.bo.mq.PayNotifyBO;
import com.dlc.shop.bean.enums.*;
import com.dlc.shop.bean.event.AllinpayBalanceOrderSuccessEvent;
import com.dlc.shop.bean.event.PaySuccessHandleOrderStockEvent;
import com.dlc.shop.bean.event.PaySuccessOrderEvent;
import com.dlc.shop.bean.event.PaySuccessScoreOrderEvent;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.param.CustomerReqParam;
import com.dlc.shop.bean.pay.PayInfoDto;
import com.dlc.shop.bean.pay.RefundInfoDto;
import com.dlc.shop.bean.vo.*;
import com.dlc.shop.common.allinpay.constant.PaySysType;
import com.dlc.shop.common.bean.PaySettlementConfig;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.constants.SegmentIdKey;
import com.dlc.shop.common.enums.PayForm;
import com.dlc.shop.common.enums.PayType;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.Arith;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.dao.OrderSettlementMapper;
import com.dlc.shop.dao.PayInfoMapper;
import com.dlc.shop.service.*;
import com.dlc.shop.util.StockUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lgh on 2018/09/15.
 */
@Slf4j
@Service
@AllArgsConstructor
public class PayInfoServiceImpl extends ServiceImpl<PayInfoMapper, PayInfo> implements PayInfoService {

    private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";
    private final RedissonClient redissonClient;
    private final ApplicationEventPublisher eventPublisher;
    private final SegmentService segmentService;
    private final RefundInfoService refundInfoService;
    private final ProductService productService;
    private final StockBillLogService stockBillLogService;
    private final SkuService skuService;
    private final PayInfoMapper payInfoMapper;
    private final NotifyTemplateService notifyTemplateService;
    private final OrderService orderService;
    private final OrderSettlementMapper orderSettlementMapper;
    private final RefundOrderSettlementService refundOrderSettlementService;
    private final SkuStockLockService skuStockLockService;
    private final AllinpayCompanyService allinpayCompanyService;
    private final FlowLogService flowLogService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayInfoDto pay(String userId, PayParam payParam, PaySettlementConfig paySettlementConfig, String bizUserId) {
        // 支付单号
        String payNo = String.valueOf(segmentService.getDateFormatSegmentId(SegmentIdKey.PAY));
        String[] orderNumbers = payParam.getOrderNumbers().split(StrUtil.COMMA);
        OrderAmountVO orderAmount = orderService.getOrdersAmountAndIfNoCancel(userId, Arrays.asList(orderNumbers), payParam.getPayType());
        //如果金额小于0.01 支付积分大于0则为纯积分支付
        double minAmount = 0.01;
        if (orderAmount.getPayAmount() < minAmount && orderAmount.getPayScore() > 0 && !Objects.equals(PayType.SCOREPAY.value(), payParam.getPayType())) {
            // 订单金额有误，无法进行支付
            throw new YamiShopBindException("yami.order.amount.error");
        }
        // 金额小于0.01且支付方式不为积分支付
        else if (orderAmount.getPayAmount() < minAmount && !Objects.equals(PayType.SCOREPAY.value(), payParam.getPayType())) {
            // 订单金额有误，无法进行支付
            throw new YamiShopBindException("yami.order.amount.error");
        }
        PayInfo payInfo = new PayInfo();
        payInfo.setPayNo(payNo);
        payInfo.setUserId(userId);
        payInfo.setPayAmount(orderAmount.getPayAmount());
        payInfo.setPayScore(orderAmount.getPayScore());
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setPayType(payParam.getPayType());
        payInfo.setVersion(0);
        payInfo.setSystemType(payParam.getSystemType());
        payInfo.setBizUserId(bizUserId);
        // 保存多个支付订单号
        payInfo.setOrderNumbers(payParam.getOrderNumbers());
        payInfo.setPayEntry(PayEntry.ORDER.value());
        payInfo.setCreateTime(new Date());
        // 保存预支付信息
        payInfoMapper.insert(payInfo);
        PayInfoDto payInfoDto = new PayInfoDto();
        payInfoDto.setBody("商城订单");
        payInfoDto.setPayAmount(orderAmount.getPayAmount());
        payInfoDto.setPayNo(payNo);
        if (Objects.equals(payParam.getPayType(), PayType.SCOREPAY.value())) {
            if (Objects.nonNull(payInfo.getPayAmount()) && payInfo.getPayAmount() > 0) {
                // 支付金额大于0的订单，不能使用积分支付
                throw new YamiShopBindException("yami.cannot.used.score.payment");
            }
            PayInfoResultBO payInfoResultBO = new PayInfoResultBO();
            payInfoResultBO.setIsPaySuccess(true);
            payInfoResultBO.setPayNo(payInfo.getPayNo());
            payInfoResultBO.setCallbackContent("积分支付成功");
            payInfoResultBO.setPayAmount(payInfo.getPayAmount());
            payInfoResultBO.setBizPayNo(payInfo.getPayNo());
            noticeOrder(payInfoResultBO, payInfo, paySettlementConfig.getPaySettlementType());
            payInfoDto.setPayType(PayType.SCOREPAY.value());
        }
        payInfoDto.setReceiveList(orderAmount.getReceiveList());
        return payInfoDto;
    }

    @Override
    public PayInfoDto buyVip(String userId, PayUserParam payUserParam) {
        PayInfo payInfo = new PayInfo();
        payInfo.setPayNo(payUserParam.getPayNo());
        payInfo.setUserId(userId);
        payInfo.setPayAmount(payUserParam.getNeedAmount());
        payInfo.setPayScore(0L);
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setPayType(payUserParam.getPayType());
        payInfo.setPayEntry(PayEntry.VIP.value());
        payInfo.setVersion(0);
        payInfo.setOrderNumbers(String.valueOf(payUserParam.getOrderIds()));
        // 保存预支付信息
        payInfoMapper.insert(payInfo);
        PayInfoDto payInfoDto = new PayInfoDto();
        payInfoDto.setPayNo(payUserParam.getPayNo());
        payInfoDto.setBody("会员等级购买");
        payInfoDto.setPayAmount(payUserParam.getNeedAmount());
        payInfoDto.setPayForm(PayForm.BUY_VIP.getValue());
        return payInfoDto;
    }

    @Override
    public PayInfoDto recharge(String userId, PayUserParam payUserParam, Integer paySysType) {
        PayInfo payInfo = new PayInfo();
        payInfo.setPayNo(payUserParam.getPayNo());
        payInfo.setUserId(userId);
        payInfo.setPayAmount(payUserParam.getNeedAmount());
        payInfo.setPayScore(0L);
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setPayType(payUserParam.getPayType());
        payInfo.setPayEntry(PayEntry.RECHARGE.value());
        payInfo.setPaySysType(paySysType);
        payInfo.setVersion(0);
        payInfo.setOrderNumbers(String.valueOf(payUserParam.getOrderIds()));
        // 保存预支付信息
        payInfoMapper.insert(payInfo);
        PayInfoDto payInfoDto = new PayInfoDto();
        payInfoDto.setPayNo(payUserParam.getPayNo());
        payInfoDto.setBody("余额充值购买");
        payInfoDto.setPayAmount(payUserParam.getNeedAmount());
        payInfoDto.setPayForm(PayForm.RECHARGE_BALANCE.getValue());
        return payInfoDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponseEntity<String> noticeOrder(PayInfoResultBO payInfoResultBO, PayInfo payInfo, Integer paySysType) {

        // 获取订单之前是否进行过支付，如果进行过则本次支付将直接退款
        String[] orderNumbers = payInfo.getOrderNumbers().split(StrUtil.COMMA);
        Arrays.sort(orderNumbers);
        List<String> orderNumberList = Arrays.asList(orderNumbers);
        RLock[] locks = new RLock[orderNumberList.size()];
        for (int i = 0; i < orderNumberList.size(); i++) {
            RLock lock = redissonClient.getLock(REDISSON_LOCK_PREFIX + orderNumberList.get(i));
            locks[i] = lock;
        }
        RLock multiLock = redissonClient.getMultiLock(locks);
        List<Order> orders;
        try {
            multiLock.lock();
            List<Order> orderStatusList = orderService.getOrdersStatus(orderNumberList);
            RefundInfoDto refundInfo = null;
            List<String> refundOrderNumbers = new ArrayList<>();
            double actualTotal = 0.0;
            for (Order order : orderStatusList) {
                actualTotal = Arith.add(actualTotal , order.getActualTotal());
                // 其中有一个订单已经支付过了
                if (!Objects.equals(order.getStatus(), OrderStatus.UNPAY.value()) && !Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
                    OrderSettlement orderSettlement = orderSettlementMapper.selectOne(Wrappers.lambdaQuery(OrderSettlement.class)
                            .eq(OrderSettlement::getOrderNumber, order.getOrderNumber()).last("limit 1"));
                    // 相同的支付单号就不判断了
                    if (Objects.nonNull(orderSettlement.getPayNo()) && Objects.equals(orderSettlement.getPayNo(), payInfo.getPayNo())) {
                        continue;
                    }
                    refundOrderNumbers.add(order.getOrderNumber());
                    if (Objects.isNull(refundInfo)) {
                        refundInfo = new RefundInfoDto();
                        refundInfo.setRefundSn(String.valueOf(segmentService.getDateFormatSegmentId(SegmentIdKey.REFUND)));
                        refundInfo.setPayNo(payInfo.getPayNo());
                        refundInfo.setRefundAmount(payInfo.getPayAmount());
                        refundInfo.setOnlyRefund(1);
                        refundInfo.setRefundType(RefundKindEnum.REPEAT_PAY.value());
                    }
                }
            }
            // 记录可以有多份 但是只退一次款
            if (Objects.nonNull(refundInfo)) {
                refundInfo.setRefundOrderNumbers(refundOrderNumbers);
                Boolean refundStatus = refundInfoService.doRefund(refundInfo);
                List<RefundInfo> refundInfoList = refundInfoService.list(new LambdaQueryWrapper<RefundInfo>().eq(RefundInfo::getRefundId, refundInfo.getRefundSn()));
                refundInfoList.forEach(item -> {
                    item.setRefundStatus(refundStatus ? RefundStatusEnum.SUCCEED.value() : RefundStatusEnum.DISAGREE.value());
                    item.setCallbackContent("重复支付的退款处理");
                    item.setCallbackTime(new Date());
                });
                refundInfoService.updateRefundStatus(refundInfoList);
                // 标记为退款
                markerRefund(payInfo.getPayNo());
                return ServerResponseEntity.success(payInfoResultBO.getSuccessString());
            }

            // 如果订单实付金额与支付金额不一致，直接退款
            if(actualTotal != payInfo.getPayAmount()){
                refundInfo = new RefundInfoDto();
                refundInfo.setRefundOrderNumbers(refundOrderNumbers);
                refundInfo.setRefundSn(String.valueOf(segmentService.getDateFormatSegmentId(SegmentIdKey.REFUND)));
                refundInfo.setPayNo(payInfo.getPayNo());
                refundInfo.setRefundAmount(payInfo.getPayAmount());
                refundInfo.setOnlyRefund(1);
                refundInfo.setRefundType(RefundKindEnum.BEYOND_PAY.value());
                refundInfoService.doRefund(refundInfo);
                // 标记为退款
                markerRefund(payInfo.getPayNo());
                return ServerResponseEntity.success(payInfoResultBO.getSuccessString());
            }

            // 真正的支付成功
            PayInfoService payInfoService = (PayInfoService) AopContext.currentProxy();
            orders = payInfoService.paySuccess(payInfoResultBO, orderNumberList, payInfo,paySysType);
        } finally {
            try {
                multiLock.unlock();
            } catch (Exception e) {
                log.error("Exception:", e);
            }
        }
        // 添加支付成功的用户操作记录
        flowLogService.paySuccessFlowLog(payInfo.getSystemType(), payInfo.getOrderNumbers(), payInfo.getUserId());
        return ServerResponseEntity.success(payInfoResultBO.getSuccessString());
    }

    private void handleActualTotal(Double actualTotal, List<Order> orderStatusList, RefundInfoDto refundInfo, List<String> refundOrderNumbers, PayInfo payInfo){
        for (Order order : orderStatusList) {
            actualTotal = Arith.add(actualTotal , order.getActualTotal());
            // 其中有一个订单已经支付过了
            if (!Objects.equals(order.getStatus(), OrderStatus.UNPAY.value()) && !Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
                OrderSettlement orderSettlement = orderSettlementMapper.selectOne(Wrappers.lambdaQuery(OrderSettlement.class)
                        .eq(OrderSettlement::getOrderNumber, order.getOrderNumber()).last("limit 1"));
                // 相同的支付单号就不判断了
                if (Objects.nonNull(orderSettlement.getPayNo()) && Objects.equals(orderSettlement.getPayNo(), payInfo.getPayNo())) {
                    continue;
                }
                refundOrderNumbers.add(order.getOrderNumber());
                if (Objects.isNull(refundInfo)) {
                    refundInfo = new RefundInfoDto();
                    refundInfo.setRefundSn(String.valueOf(segmentService.getDateFormatSegmentId(SegmentIdKey.REFUND)));
                    refundInfo.setPayNo(payInfo.getPayNo());
                    refundInfo.setRefundAmount(payInfo.getPayAmount());
                    refundInfo.setOnlyRefund(1);
                    refundInfo.setRefundType(RefundKindEnum.REPEAT_PAY.value());
                }
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Order> paySuccess(PayInfoResultBO payInfoResultBO, List<String> orderNumbers, PayInfo payInfo, Integer paySysType) {
        String payNo = payInfoResultBO.getPayNo();
        String bizPayNo = payInfoResultBO.getBizPayNo();
        // 标记为支付成功
        updatePayInfo(payInfoResultBO, payNo, bizPayNo,paySysType);

        List<OrderItem> allOrderItem = new ArrayList<>();
        List<Order> orders = orderService.listOrderAndOrderItemByOrderNumber(orderNumbers);
        for (Order order : orders) {
            allOrderItem.addAll(order.getOrderItems());
        }
        List<Order> refundOrderList = new ArrayList<>();
        List<Order> successOrderList = new ArrayList<>();
        for (Order order : orders) {
            OrderSettlement orderSettlement = orderSettlementMapper.selectOne(new LambdaQueryWrapper<OrderSettlement>().eq(OrderSettlement::getOrderNumber, order.getOrderNumber()).last("limit 1"));
            orderSettlement.setPayNo(payNo);
            orderSettlement.setPayType(payInfo.getPayType());
            orderSettlementMapper.updateById(orderSettlement);

            // 先检查是否虚拟商品过期，是的话直接退款
            if (Objects.equals(order.getOrderMold(), 1) && Objects.nonNull(order.getWriteOffEnd())
                    && DateUtil.compare(order.getWriteOffEnd(), new Date()) < 0) {
                refundOrderList.add(order);
                // 此时还需要判断下订单是否已取消，如果不是已取消则需要回退库存和改变订单状态
                if (!Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
                    orderService.cancelOrders(Collections.singletonList(order));
                }
                continue;
            }

            if (!Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
                successOrderList.add(order);
                continue;
            }

            // 超时付款，订单已取消还原了库存，这里给他再扣一次
            if (Objects.equals(order.getOrderType(), OrderType.SECKILL.value())) {
                // 扣除秒杀商品虚拟库存or退款
                eventPublisher.publishEvent(new PaySuccessHandleOrderStockEvent(successOrderList, refundOrderList, order));
                break;
            } else {
                // 普通订单
                if (handleOrderStock(order)) {
                    successOrderList.add(order);
                } else {
                    refundOrderList.add(order);
                }
            }
        }

        OrderSettlement orderSettlement = orderSettlementMapper.selectOne(Wrappers.lambdaQuery(OrderSettlement.class).eq(OrderSettlement::getPayNo, payNo).last("limit 1"));
        if (CollectionUtils.isNotEmpty(refundOrderList)) {
            orderNumbers = successOrderList.stream().map(Order::getOrderNumber).collect(Collectors.toList());
            List<String> refundOrderNumbers = refundOrderList.stream().map(Order::getOrderNumber).collect(Collectors.toList());
            // 成功订单不为空在修改订单信息
            if (CollectionUtils.isNotEmpty(successOrderList)) {
                // 修改订单结算信息
                if (orderSettlementMapper.updateToOrderNumbers(orderNumbers, bizPayNo, orderSettlement.getVersion()) < 1) {
                    // 结算信息已更改
                    throw new YamiShopBindException("yami.modified.settlement.information");
                }
                // 将订单改为已支付状态
                orderService.updateByToPaySuccess(orderNumbers, payInfo.getPayType(),paySysType);
            }
            // 退款操作
            List<OrderSettlement> refundOrderSettlements = orderSettlementMapper.listDetailByOrderNumbers(refundOrderNumbers);
            double refundAmount = 0.0;
            for (OrderSettlement refundOrderSettlement : refundOrderSettlements) {
                refundAmount = Arith.add(refundAmount, refundOrderSettlement.getPayAmount());
            }
            orderSettlement.setPayAmount(refundAmount);
            // 更新退款结算记录
            refundNoStockOrderSettlement(orderSettlement);
        } else {
            // 修改订单结算信息
            if (orderSettlementMapper.updateToPay(payNo, bizPayNo, orderSettlement.getVersion()) < 1) {
                // 结算信息已更改
                throw new YamiShopBindException("yami.modified.settlement.information");
            }
            // 将订单改为已支付状态
            orderService.updateByToPaySuccess(orderNumbers, payInfo.getPayType(), paySysType);
        }
        if (CollectionUtils.isEmpty(successOrderList)) {
            return orders;
        }
        successOrderList.forEach(order -> order.setPaySysType(paySysType));
        // 处理下相关活动、分账、分销推送，库存的解锁和消息推送
        handlerStockAndMsg(payInfo.getPayNo(), orderNumbers, allOrderItem, successOrderList, paySysType);
        return orders;
    }

    private void updatePayInfo(PayInfoResultBO payInfoResultBO, String payNo, String bizPayNo, Integer paySysType) {
        PayInfo newPayInfo = new PayInfo();
        newPayInfo.setPayNo(payNo);
        newPayInfo.setBizPayNo(bizPayNo);
        newPayInfo.setCallbackContent(payInfoResultBO.getCallbackContent());
        newPayInfo.setCallbackTime(new Date());
        newPayInfo.setPayStatus(PayStatus.PAYED.value());
        newPayInfo.setPaySysType(paySysType);
        // 未支付状态才能更改为已支付，防止重复支付
        boolean update = update(newPayInfo, new LambdaUpdateWrapper<PayInfo>().eq(PayInfo::getPayNo, newPayInfo.getPayNo()).eq(PayInfo::getPayStatus, PayStatus.UNPAY.value()));
        if (!update) {
            throw new YamiShopBindException("yami.order.payed.repeat.operation");
        }
    }

    private void handlerStockAndMsg(String payNo, List<String> orderNumbers, List<OrderItem> allOrderItem, List<Order> successOrderList, Integer paySysType) {
        // 消息推送-支付成功
        notifyTemplateService.sendNotifyOfPaySuccess(successOrderList);
        Integer orderType = successOrderList.get(0).getOrderType();
        //如果是积分订单只需添加平台结算记录,不是则发送支付成功事件
        if (Objects.equals(successOrderList.get(0).getOrderType(), OrderType.SCORE.value())) {
            Order order = new Order();
            order.setOrderNumber(successOrderList.get(0).getOrderNumber());
            order.setSettledTime(new Date());
            order.setIsSettled(1);
            order.setShopId(Constant.PLATFORM_SHOP_ID);
            order.setActualTotal(successOrderList.get(0).getActualTotal());
            order.setPaySysType(successOrderList.get(0).getPaySysType());
            // 修改订单为已结算状态
            orderService.update(order, new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, order.getOrderNumber()));
            eventPublisher.publishEvent(new PaySuccessScoreOrderEvent(order, allOrderItem, payNo));
        } else {
            List<Order> orderList = successOrderList.stream().filter(order -> order.getOrderMold() == 1 && !Objects.equals(successOrderList.get(0).getOrderType(), OrderType.GROUP.value())).collect(Collectors.toList());
            // 虚拟商品支付后，订单状态是已发货
            if (CollUtil.isNotEmpty(orderList)) {
                for (Order order : orderList) {
                    Order newOrder = new Order();
                    // 修改订单为已发货状态
                    newOrder.setStatus(OrderStatus.CONSIGNMENT.value());
                    newOrder.setDvyTime(new Date());
                    newOrder.setUpdateTime(new Date());
                    newOrder.setOrderId(order.getOrderId());
                    orderService.updateById(newOrder);
                }
            }
            eventPublisher.publishEvent(new PaySuccessOrderEvent(successOrderList, allOrderItem, payNo));
        }
        PayNotifyBO payNotifyBO = new PayNotifyBO();
        payNotifyBO.setOrderNumbers(orderNumbers);
        // 非秒杀订单，共用的库存
        if (!Objects.equals(orderType, OrderType.SECKILL.value())) {
            skuStockLockService.markerStockUse(allOrderItem);
        }
        if(Objects.equals(paySysType,PaySysType.ALLINPAY.value())) {
            double totalAmount = 0.0;
            for (Order order : successOrderList) {
                totalAmount = Arith.add(totalAmount,order.getActualTotal());
            }
            eventPublisher.publishEvent(new AllinpayBalanceOrderSuccessEvent(payNo, UserBalanceLogType.PAY.value(),successOrderList.get(0).getUserId(),totalAmount));
        }
    }

    private void refundNoStockOrderSettlement(OrderSettlement orderSettlement) {
        RefundInfoDto refundInfo = new RefundInfoDto();
        refundInfo.setPayNo(orderSettlement.getPayNo());
        String refundSn = String.valueOf(segmentService.getDateFormatSegmentId(SegmentIdKey.REFUND));
        refundInfo.setRefundSn(refundSn);
        refundInfo.setRefundAmount(orderSettlement.getPayAmount());
        refundInfo.setPayNo(orderSettlement.getPayNo());
        refundInfo.setRefundOrderNumbers(Collections.singletonList(orderSettlement.getOrderNumber()));
        Boolean refundSuccess = refundInfoService.doRefund(refundInfo);
        PayType payType = refundInfo.getPayType();
        if (!refundSuccess && Objects.equals(payType, PayType.PAYPAL) && PayType.isAliPay(payType)) {
            return;
        }
        Date date = new Date();
        RefundOrderSettlement refundOrderSettlement = new RefundOrderSettlement();
        refundOrderSettlement.setOrderNumber(orderSettlement.getOrderNumber());
        refundOrderSettlement.setOrderPayNo(orderSettlement.getPayNo());
        refundOrderSettlement.setRefundSn(refundSn);
        refundOrderSettlement.setPayType(orderSettlement.getPayType());
        refundOrderSettlement.setRefundAmount(orderSettlement.getPayAmount());
        refundOrderSettlement.setOrderTotalAmount(orderSettlement.getPayAmount());
        refundOrderSettlement.setUserId(orderSettlement.getUserId());
        refundOrderSettlement.setRefundStatus(2);
        refundOrderSettlement.setCreateTime(date);
        refundOrderSettlement.setUpdateTime(date);
        refundOrderSettlementService.save(refundOrderSettlement);
    }


    /**
     * 扣除库存
     *
     * @param order
     * @return
     */
    private boolean handleOrderStock(Order order) {
        List<OrderItem> orderItems = order.getOrderItems();
        Map<Long, SkuStockVO> skuStockLockMap = new HashMap<>(orderItems.size());
        for (OrderItem orderItem : orderItems) {
            Product product = productService.getProductInfo(orderItem.getProdId());
            if (product == null) {
                // 购物车包含无法识别的商品
                return false;
            }
            SkuStockVO skuStockVO = skuStockLockMap.get(orderItem.getSkuId());
            if (Objects.isNull(skuStockVO)) {
                skuStockVO = new SkuStockVO(orderItem.getOrderNumber(), orderItem.getSkuId(), orderItem.getProdCount(), orderItem.getStockPointId());
                skuStockLockMap.put(orderItem.getSkuId(), skuStockVO);
                continue;
            }
            skuStockVO.setStock(skuStockVO.getStock() + orderItem.getProdCount());
        }

        String stockInfo = skuStockLockService.lockStock(skuStockLockMap.values().stream().toList());
        // 库存不足或者商品下架
        if (!stockInfo.contains(StrUtil.COMMA)) {
            return false;
        }
        StockUtil.setSkuStockResult(stockInfo, order.getOrderItems());
        // 生成出库明细
        stockBillLogService.generateStockLogOfOrderList(
                Collections.singletonList(order), StockBillType.PURCHASE_OUTBOUND.value(), StockType.OUT_OF_STOCK.value());
        return true;
    }

    @Override
    public Integer queryPay(String orderNumbers, String userId, Integer payEntry) {
        return payInfoMapper.queryPay(orderNumbers, userId, payEntry);
    }

    @Override
    public void markerRefund(String payNo) {
        PayInfo payInfo = new PayInfo();
        payInfo.setPayNo(payNo);
        payInfo.setPayStatus(PayStatus.REFUND.value());
        update(payInfo, Wrappers.lambdaUpdate(PayInfo.class).eq(PayInfo::getPayNo, payNo));
    }

    @Override
    public AccountDetailVO getIncomeAccountDetail(Date startTime, Date endTime, String shopName) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        AccountDetailVO accountDetailVO = payInfoMapper.getIncomeAccountDetail(startTime, endTime, shopName, paySysType);
        return refundInfoService.getAccountDetailVO(accountDetailVO);
    }

    @Override
    public AccountDetailVO getPlatformIncomeAccountDetail(Date startTime, Date endTime) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        AccountDetailVO platformAccountDetail = payInfoMapper.getPlatformAccountDetail(startTime, endTime, paySysType);
        return refundInfoService.getAccountDetailVO(platformAccountDetail);
    }

    @Override
    public IPage<ShopAccountVO> pageIncomeAccountDetail(PageParam<ShopAccountVO> page, CustomerReqParam accountSearchDTO) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        return payInfoMapper.pageAllIncomeAccount(page, accountSearchDTO.getStartTime(), accountSearchDTO.getEndTime(), accountSearchDTO.getShopName(), paySysType);
    }

    @Override
    public IPage<ShopAccountDetailVO> pageShopIncomeAccountDetail(PageParam<ShopAccountDetailVO> page, CustomerReqParam customerReqParam) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        IPage<ShopAccountDetailVO> accountDetailPage;
        if (Objects.equals(customerReqParam.getShopId(), Constant.PLATFORM_SHOP_ID)) {
            accountDetailPage = payInfoMapper.pagePlatformIncomeAccountDetail(page, customerReqParam.getStartTime(), customerReqParam.getEndTime(), paySysType);
        } else {
            accountDetailPage = payInfoMapper.pageShopIncomeAccountDetail(page, customerReqParam.getStartTime(), customerReqParam.getEndTime(), customerReqParam.getShopId(), paySysType);
        }
        return accountDetailPage;
    }

    @Override
    public List<ShopAccountDetailVO> listIncomeAccountDetail(CustomerReqParam customerReqParam) {
        Integer paySysType = allinpayCompanyService.getIsAllinpay() ? PaySysType.ALLINPAY.value() : PaySysType.DEFAULT.value();
        return payInfoMapper.listIncomeAccountDetail(customerReqParam.getStartTime(), customerReqParam.getEndTime(), customerReqParam.getShopName(), paySysType);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServerResponseEntity<String> settlementAllinpayOrder(PayInfoResultBO payInfoResultBO, PayInfo payInfo) {
        Order order = orderService.getOrderAndOrderItemByOrderNumber(payInfo.getOrderNumbers());
        if (Objects.isNull(order)) {
            return ServerResponseEntity.success(payInfoResultBO.getSuccessString());
        }
        orderService.orderCommissionSettlement(Collections.singletonList(order));
        // 移除缓存
        List<OrderItem> orderItems = order.getOrderItems();
        for (OrderItem orderItem : orderItems) {
            productService.removeProdCacheByProdId(orderItem.getProdId());
            skuService.removeSkuCacheBySkuId(orderItem.getSkuId(), orderItem.getProdId());
        }
        return ServerResponseEntity.success(payInfoResultBO.getSuccessString());
    }

}
